#ifndef SPL_VECTOR
#define SPL_VECTOR

template <class T, UINT N = 10>
class DLLEXPORT Vector
{
private:
  T*    mBuffer;
  UINT  mBufferSize;
  UINT  mBufferLength;

public:
  SPLINL UINT getSize() const
  {
    return mBufferSize;
  }

  SPLINL UINT getLength() const
  {
    return mBufferLength;
  }

  SPLINL const T& get(UINT iIndex) const
  {
    ASSERT(iIndex >= 0 && iIndex < mBufferLength);
    ASSERT(mBuffer);
    return mBuffer[iIndex];
  }

  SPLINL T& getTop() const
  {
    ASSERT(mBufferLength > 0);
    ASSERT(mBuffer);
    return mBuffer[mBufferLength - 1];
  }

  SPLINL const T* getBuffer() const
  {
    return mBuffer;
  }

  SPLINL UINT add(const T& iItem)
  {
    if (mBufferLength == mBufferSize)
      setSize(mBufferSize + N);

    mBuffer[mBufferLength++] = iItem;
    return mBufferLength - 1;
  }

  SPLINL VOID swap(UINT iIndex1, UINT iIndex2)
  {
    ASSERT(iIndex1 >= 0 && iIndex1 < mBufferLength);
    ASSERT(iIndex2 >= 0 && iIndex2 < mBufferLength);
    ASSERT(iIndex1 != iIndex2);
    ASSERT(mBuffer);

    T wTemp = mBuffer[iIndex1];

    mBuffer[iIndex1] = mBuffer[iIndex2];
    mBuffer[iIndex2] = wTemp;
  }

  SPLINL VOID clear()
  {
    delete[] mBuffer;

    mBuffer = NULL;
    mBufferSize = mBufferLength = 0;
  }

  SPLINL VOID empty()
  {
    mBufferLength = 0;
  }

  INT   getIndex(const T& iItem) const;
  VOID  setSize(UINT iSize);
  //VOID  setLength(UINT iLength);
  UINT  remove(UINT iIndex);
  UINT  remove(UINT iIndex, UINT iCount);

  SPLINL T& operator[](UINT iIndex)
  {
    ASSERT(iIndex < (INT)mBufferSize);
    ASSERT(mBuffer);

    if (iIndex >= mBufferLength)
      mBufferLength = iIndex + 1;

    return mBuffer[iIndex];
  }

  SPLINL Vector() :
    mBuffer(NULL),
    mBufferSize(0),
    mBufferLength(0)
  {
  }

  SPLINL Vector(UINT iSize) :
    mBuffer(NULL),
    mBufferSize(0),
    mBufferLength(0)
  {
    setSize(iSize);
  }

  SPLINL ~Vector()
  {
    delete[] mBuffer;
  }
};

template <class T, UINT N>
INT   Vector<T, N>::getIndex(const T& iItem) const
{
  ASSERT(iItem);
  ASSERT(mBuffer);

  for (UINT i = 0; i < mBufferLength; ++i)
  {
    if (mBuffer[i] == iItem)
      return (INT)i;
  }

  return -1;
}
/*
template <class T, UINT N>
VOID  Vector<T, N>::setLength(UINT iSize)
{
  if (mBufferLength == iSize) return;

  ASSERT(iSize >= 0);

  if (mBufferLength + iSize > mBufferSize)
    setSize(mBufferSize + N);

  mBufferLength = iSize;
}
*/
template <class T, UINT N>
VOID  Vector<T, N>::setSize(UINT iSize)
{
  if (mBufferSize == iSize) return;

  ASSERT(iSize >= 0);

  T* wNewBuffer = new T[iSize];

  if (mBuffer)
  {
    mBufferLength = min(iSize, mBufferLength);
    memcpy(wNewBuffer, mBuffer, mBufferLength * sizeof(T));

    delete[] mBuffer;
  }
  else
  {
    mBufferLength = 0;
  }

  mBuffer = wNewBuffer;
  mBufferSize = iSize;
}

template <class T, UINT N>
UINT  Vector<T, N>::remove(UINT iIndex)
{
  ASSERT(iIndex >= 0 && iIndex < mBufferLength);
  ASSERT(mBuffer);

  /*UINT wSize = mBufferLength - 1;
  wSize = wSize - wSize % N + N;*/

  for (UINT i = iIndex + 1; i < mBufferLength; ++i)
    mBuffer[i - 1] = mBuffer[i];

  /*if (wSize < mBufferSize)
    setSize(wSize);*/

  return --mBufferLength;
}

template <class T, UINT N>
UINT  Vector<T, N>::remove(UINT iIndex, UINT iCount)
{
  ASSERT(iIndex >= 0 && iIndex + iCount <= mBufferLength && iCount > 0);
  ASSERT(mBuffer);

  UINT wSize = mBufferLength - iCount;
  wSize = wSize - wSize % N + N;

  UINT wPadding = mBufferLength - (iIndex + iCount);

  mBufferLength -= iCount;

  for (UINT i = 0; i < wPadding; ++i)
    mBuffer[iIndex + i] = mBuffer[iIndex + iCount + i];

  if (wSize < mBufferSize)
    setSize(wSize);

  return mBufferLength;
}

#endif